///\file
#include <data_base.h>
#include <stdlib.h>
#include <chronometer.h>

// Tamanho das strings utilizadas
#define NOME_SIZE	102
#define CPF_SIZE	13
#define RG_SIZE		11
#define CARGO_SIZE	32

static FILE*	clientTime;

// Executa o cliente
void run( CLIENT* );
// Exibe o menu e retorna a opção escolhida
char menu();
// Inicializa um registro, alocando os vetores
void client_createRegistry( Registry* reg );
// Destrói um registro, desalocando os vetores
void client_destroyRegistry( Registry* reg );
// Lê um registro digitado pelo usuario
void client_readRegistry( Registry* reg );
// Exibe um registro na tela
void client_printRegistry( Registry* reg );
// Troca \n por \0
void client_fixString( char *str );
// Solicita operação de inserção
void client_insert( Registry* reg, CLIENT* client );
// Solicita operação de remoção
void client_remove( Registry* reg, CLIENT* client );
// Solicita operação de busca
void client_search( Registry* reg, CLIENT* client );

int main( int argc, char **argv ) {
	CLIENT *client;

	// Execução errada
	if (argc < 3) {
		printf("Error: too few arguments\n");
		printf("client <hostname> <filename>\n");
		return 1;
	}

	// Iniciar conexão
	client = clnt_create(argv[1], PROGRAM, VERSION, "tcp");
	if (client == NULL) {
		printf("Error: could not connect to server\n");
		return 1;
	}

	clientTime = fopen(argv[2],"w");
	// Executar cliente
	run( client );
	fclose(clientTime);

	return 0;
}

/**
 * \brief Executa o cliente apos iniciada a conexão
 * \param client O cliente criado pelo RPC
 * */
void run( CLIENT *client ) {
	char option;
	Registry reg;

	client_createRegistry(&reg);

	do {
		option = menu();
		switch (option) {
			case '1':
				client_readRegistry( &reg );
				client_insert( &reg, client );
				break;
			case '2':
				client_readRegistry( &reg );
				client_remove( &reg, client );
				break;
			case '3':
				client_readRegistry( &reg );
				client_search( &reg, client );		
				break;
			case '4':
				break;
			default:
				printf("There is no option %c\n", option);
		}
	} while (option != '4');

	client_destroyRegistry(&reg);
}

/**
 * \brief Solicita ao servidor a operação de inserção
 * \param reg Registro a inserir
 * \param client O cliente criado pelo RPC
 */

void client_insert( Registry *reg, CLIENT *client ) {
	chronometer_t crono;

	printf("Sending insert request:\n");
	client_printRegistry(reg);

	chronometerStart(&crono);
	insert_1(reg, client);
	chronometerPause(&crono);

	fprintf(clientTime,"%03ld.%09ld\n",chronometerGetSec(crono),chronometerGetNSec(crono));

	printf("Done.\n");
}

/**
 * \brief Solicita ao servidor a operação de remoção
 * \param reg Registro a ser removido
 * \param client O cliente criado pelo RPC
 */
void client_remove( Registry *reg, CLIENT *client ) {
	chronometer_t crono;

	printf("Sending remove request:\n");
	client_printRegistry( reg );

	chronometerStart(&crono);
	remove_1(reg, client);
	chronometerPause(&crono);

	fprintf(clientTime,"%03ld.%09ld\n",chronometerGetSec(crono),chronometerGetNSec(crono));

	printf("Done.\n");
}

/**
 * \brief Solicita ao servidor a operação de busca
 * \param reg Registro a ser buscado
 * \param client Cliente gerado pelo RPC
 */

void client_search( Registry *reg, CLIENT *client ) {
	chronometer_t crono;

	printf("Sending search request:\n");
	client_printRegistry(reg);

	// Obtendo lista de resultados
	chronometerStart(&crono);
	RegistryList *list = search_1( reg, client );
	chronometerPause(&crono);

	fprintf(clientTime,"%03ld.%09ld\n",chronometerGetSec(crono),chronometerGetNSec(crono));

	if (list == NULL) {
		printf("ERROR: could not get search result list.\n");
		clnt_perror(client,NULL);	
		return;
	}

	// Percorrendo vetor de resultados
	Registry *now = list->list.list_val;
	int i;

	printf("\nFound %d results.\n", list->list.list_len);
	for (i = 0; i < list->list.list_len; i++) {
		client_printRegistry(now);
		now++;
	}
}

/**
 * \brief Exibe um menu e retorna a opção selecionada
 * \return Opção selecionada
 */
char menu() {
	printf("\n\nDatabase Server menu:\n");
	printf("1. Insert new registry\n");
	printf("2. Remove registry\n");
	printf("3. Search registry\n");
	printf("4. Quit\t\t\t> ");  

	fflush(stdin);
	char c = getchar();
	getchar();
	printf("\n");
	return c;
}

/**
 * \brief Inicializa um registro, alocando os vetores
 * \param reg Registro a ser inicializado
 */
void client_createRegistry( Registry *reg ) {
	reg->nome = (char*) malloc (sizeof(char)*NOME_SIZE);
	reg->CPF = (char*) malloc (sizeof(char)*CPF_SIZE);
	reg->RG = (char*) malloc (sizeof(char)*RG_SIZE);
	reg->cargo = (char*) malloc (sizeof(char)*CARGO_SIZE);
}

/**
 * \brief Destrói um registro, desalocando vetores
 * \param reg Registro a ser destruido
 */
void client_destroyRegistry( Registry *reg ) {
	free(reg->nome);
	free(reg->CPF);
	free(reg->RG);
	free(reg->cargo);
}

/**
 * \brief Lê um registro da entrada
 * \param reg Registro onde armazenar a leitura
 */
void client_readRegistry( Registry *reg ) {
	printf("\nNome:\t" );
	fflush(stdin);
	fgets(reg->nome, NOME_SIZE, stdin );
	client_fixString(reg->nome);

	printf("CPF:\t");
	fflush(stdin);
	fgets(reg->CPF, CPF_SIZE, stdin );
	client_fixString(reg->CPF);

	printf("RG:\t" );
	fflush(stdin);
	fgets(reg->RG, RG_SIZE, stdin );
	client_fixString(reg->RG);

	printf("Cargo: \t");
	fflush(stdin);
	fgets(reg->cargo, CARGO_SIZE, stdin );
	client_fixString(reg->cargo);

}

/**
 * \brief Exibe um registro na tela
 * \param reg Registro a ser exibido
 */
void client_printRegistry( Registry *reg ) {
	printf("[ %s | %s | %s | %s ]\n", reg->nome, reg->CPF, reg->RG, reg->cargo );
}

/**
 * \brief Troca o primeiro \\n por \0
 * \param str String a ser analisada
 */
void client_fixString( char *str ) {
	while (*str != '\n')
		str++;

	*str = '\0';
}
